#include <iostream>
#include <cstring>
#include <gtk/gtk.h>
#include "variables_data.h"
#include "windows_settings.h"
#include "ingame_operations.h"
using namespace std;

extern GtkBuilder *builder;

//Ridichiarazione con parola chiave extern delle variabili globali usate nei vari file.
extern bool flag;

extern giocatori gamer, campo_gioco[6][7];

extern const char *P1, *P2;

extern unsigned int campo_gioco_pos[6][7];
extern unsigned int red_cell, yellow_cell;
extern unsigned int token;
extern unsigned int r_m_won, y_m_won; 

/**
 * Nel primo 'blocco' è effettuato il controllo orizzontale in cui vengono scandite
 * le celle della prima riga del campo a partire dal basso, da sinistra verso destra;
 * una volta scandita questa riga si procede con quella precedente allo stesso modo
 * fino in cima finchè non viene trovato un vincitore. Se questo non c'è allora 
 * si passa ai controlli verticali descritti in seguito.
 * Nel conteggio della sequenza di celle dello stesso colore basta verificare che  
 * red/yellow_cell sia uguale a 3 poichè nell'if 'madre' è implicito il fatto che  
 * la prima cella da cui si parte sia già o rossa o gialla.
 *
 * Nel secondo 'blocco' sono svolti i controlli verticali in cui vengono scandite le
 * celle dal basso verso l'alto della prima colonna (a sinistra) e se qui non viene 
 * trovato il vincitore si passa alla colonna successiva andando verso destra. 
 * Se neanche in questo modo viene trovato un vincitore, verranno svolti i controlli
 * obliqui nell'apposita funzione ::controlli_obliqui.
 * 
 * @param[in] g_player E' l'enumerato che vale player1 la prima chiamata e la seconda player2.
 * @param[in] g_cell La prima chiamata vale red_cell la seconda vale yell_cell e indicano
 * 					 quante celle dello stesso colore sono presenti in fila; è passato per 
 *					 riferimento perchè se non viene trovato un vincitore è resettato a zero.
 * @param[in] g_won Anche questa variabile globale è passata per riferimento e la prima chiamata
 *					tiene il conto delle partite totali vinte dal rosso e la seconda dal giallo.
 * @param[in] g_label Questa stringa la prima chiamata contiene 'dialog3' e serve in caso di 
 * 			  		  vittoria per mostare la relativa finestra. La seconda chiamata vale 'dialog4'.
 * 
 * @param[in] g_won Questa stringa contiene invece la label relativa al nome del giocatore che ha vinto
 * 					quindi la prima chimata vale 'ROSSO' (oppure il nome impostato dall'utente)
 *					e la seconda chiamata vale 'GIALLO' (oppure il nome impostato dall'utente).
 */
static void check_horiz_plus_verti(giocatori g_player, unsigned int &g_cell, 
								   unsigned int &g_won, const char g_label[], const char win_label[])
{
//controllo orizzontale
int h=5;
while(h>=0){
	for(int j=0; j<6; j++)	{
		if(campo_gioco[h][j]==campo_gioco[h][j+1] && campo_gioco[h][j]==g_player){
			g_cell++;

			if(g_cell==3){
				set_index_sensitive(42, false);

				GtkLabel *label =GTK_LABEL(gtk_builder_get_object(builder,win_label));
				if(strcmp(win_label,"label75")==0)
					gtk_label_set_text(label, P1);
				else
					gtk_label_set_text(label, P2);

				GtkWidget *g_dialog =GTK_WIDGET(gtk_builder_get_object(builder,g_label));
				gtk_widget_show_all(g_dialog);
				g_won++;
				points_updater();
					     }
																				 }
		else
			g_cell=0;			
							}//fine ciclo for
h--;	
           }//fine while

D1(cout<<"controllo orizzontale terminato, "<<
	"non è stato trovato un vincitore sulle righe"<<endl);
//controllo verticale
int k=0;
while(k<6){
	for(int i=5; i>0; i--)	{
		if(campo_gioco[i][k]==campo_gioco[i-1][k] && campo_gioco[i][k]==g_player){
			g_cell++;

			if(g_cell==3){
				set_index_sensitive(42, false);

				GtkLabel *label =GTK_LABEL(gtk_builder_get_object(builder,win_label));
				if(strcmp(win_label,"label75")==0)
					gtk_label_set_text(label, P1);
				else
					gtk_label_set_text(label, P2);

				GtkWidget *g_dialog =GTK_WIDGET(gtk_builder_get_object(builder,g_label));
				gtk_widget_show_all(g_dialog);
				g_won++;
				points_updater();
							}
																				 }
		else
			g_cell=0;			
							}//fine ciclo for	
k++;	
          }//fine while
D1(cout<<"controllo verticale terminato, "<<
	"non è stato trovato un vincitore sulle colonne"<<endl);
}

/**
 * Funzione che controlla se c'è un vincitore in una riga o in una colonna
 * tramite le due chiamate della funzione ::check_horiz_plus_verti  
 * a cui vengono passati 5 parametri.
 * La prima chiamata è relativa al g1 e la seconda al g2.
 */
static void controlli_orizzontali_verticali()
{
	check_horiz_plus_verti(player1, red_cell, r_m_won, "dialog3", "label75");

	check_horiz_plus_verti(player2, yellow_cell, y_m_won, "dialog4", "label76");
}

/**
 * Funzione che controlla il vincitore nella diagonale: dal basso verso l'alto se
 * sup_inf=true, dall'alto verso il basso se sup_inf=false (in questo modo si può
 * capire da quale ciclo è stata invocata). 
 * La funzione chiamante passa a questa l'indice di riga e colonna che individua la
 * cella rossa o gialla e da quela si controlla se nella stessa diagonale sono 
 * presenti altre celle. Questo ciclo va avanti fino a che il valore della cella attuale
 * non raggiunge un totale di 4 oppure è diverso dal valore precendente.
 * All'uscita dal ciclo poi se il numero di celle dello stesso colore è 4 si invoca
 * la funzione ::actual_winner con i vari parametri per mostrare correttamente
 * la finestra di vittoria relativa al giocatore rosso o giallo.
 *
 * @param[in] row E' l'indice di riga suddetto.
 * @param[in] col E' l'indice di colonna suddetto.
 * @param[in] sup_inf Variabile booleana che indica se cercare nella diagonale
 *  		  		  'ascendente'(true) o nella diagonale 'discendente'(false).
 */
static void controllo_diagonale(int row, int col, bool sup_inf)
{	
giocatori colore;
int z;

if(campo_gioco[row][col]==player1)
	colore=player1;
else
	colore=player2;

if(sup_inf==true){
	row--, col++;
	for(z=0; z<3; z++){ //viene eseguito solo 3 volte perchè 
		if(campo_gioco[row][col]==colore)//la prima cella è già considerata
			row--, col++;	
		else
			break;	
					  }
			     }
else{
	row++, col++;
	for(z=0; z<3; z++){ 
		if(campo_gioco[row][col]==colore)
			row++, col++;	
		else
			break;	
					  }
	}

if(z==3 && colore==player1)
	actual_winner(r_m_won, P1, "label75", "dialog3");
						  
else if(z==3 && colore==player2)
	actual_winner(y_m_won, P2, "label76", "dialog4");									
}

/**
 * Il primo ciclo scandisce le celle in obliquo individuate dagli incroci
 * delle righe 3 alla 5 compresa con le colonne dalla 0 alla 3 (compresa),
 * quindi sono le diagonali dal basso verso l'alto.
 * Mentre il secondo ciclo scandisce le celle in obliquo individuate dagli incroci 
 * delle righe 2 alla 0 compresa con le colonne dalla 0 alla 3 (compresa) quindi
 * sono le diagonali dall'alto verso il basso.
 * Questi cicli servono a controllare che le celle scandite siano vuote, perchè 
 * se viene rilevato un valore diverso da 'vuota' nella cella, viene chiamata 
 * la funzione ::controllo_diagonale.
 */
static void controlli_obliqui()
{
for(int i=3; i<6; i++){
	for(int j=0; j<4; j++){
		if(campo_gioco[i][j]==vuota)
			continue;
		else{
			D1(cout<<"trovata una cella 'colorata' nei controlli"<<
				"obliqui dal basso verso l'alto"<<endl);
			controllo_diagonale(i,j,true);
			}
						  }
					  }

for(int i=2; i>=0; i--){
	for(int j=0; j<4; j++){
		if(campo_gioco[i][j]==vuota)
			continue;
		else{
			D1(cout<<"trovata una cella 'colorata' nei controlli"<<
				"obliqui dall'alto verso il basso"<<endl);
			controllo_diagonale(i,j,false);
			}
					      }
					   }						
}
/**
 * Funzione principale che chiama i vari controlli ogni volta che si inserisce un gettone.
 * Chiama le due funzioni principali ::controlli_orizzontali_verticali e ::controlli_obliqui.
 */
void check_winner()
{	
	controlli_orizzontali_verticali();
	controlli_obliqui();
} 


